package taskman.ui;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import taskman.Task;
import taskman.xml.XmlHelper;


public class GanntViewWindow extends JFrame
{
/*This is an example of how a Gannt chart URL looks like when using Google Chart API.
 * 
 * http://chart.apis.google.com/chart?
 * chd=t:1,1,1|3,1,10|6.0,6.0,2.0
 * &chbh=14,4,4
 * &chco=ffffff00,444444,FEF693|D75C65|FEF693|FFFFFF|FEF693|000000|FEF693|9AFD92|FEF693|9AFD92
 * &chxt=y,x
 * &chds=0,59
 * &chxl=0:|Documentation|Javadoc|Proof+Read|1:|01 Apr|||||||||||||||16 Apr|||||||||||||||01 May|||||||||||||||16 May|||||||||||||||
 * &chxs=0,000000,11,1,lt,EEEEEE|1,000000,11,0,lt,DDDDDD
 * &chxtc=0,-800|1,-800
 * &chm=t20%,000000,1,0,11|t30%,000000,1,1,11|t5%,000000,1,2,11|r,99ccff44,0,0,010.44
 * &chs=600x300
 * &cht=bhs
 * &chtt=Comp+354+Tasks+Gannt+Chart
 */
	private Date minDateFound = null;
	private Date maxDateFound = null;
	
	public static void main(String[] args)
	{
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					GanntViewWindow frame = new GanntViewWindow("Comp 354 Tasks Gannt Chart",XmlHelper.loadAllTasks());
					frame.pack();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	/**
	 * Builds and displays a Gannt chart of the tasks.
	 * @param chartName The name of the charts
	 * @param tasks The tasks to display on the chart
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	public GanntViewWindow(String chartName, List<Task> tasks)
	{
		String xyAxis = parseXYAxis(tasks);
		String barsData = parseBars(tasks);
		String parsePercentCompleteData = parsePercentCompleteData(tasks);
		String colors = parseBarColors(tasks);
		String query = "chd="+barsData+
		"&chbh=14,4,4"+
		"&chco="+colors+
		"&chxt=y,x"+
		"&chds=0,59"+
		"&chxl="+xyAxis+
		"&chxs=0,000000,11,1,lt,EEEEEE|1,000000,11,0,lt,DDDDDD"+
		"&chxtc=0,-800|1,-800"+
		"&chm="+parsePercentCompleteData+"|r,99ccff44,0,0,010.44"+
		"&chs=600x"+tasks.size()*33+ // for every task we will increase the height of the graph by 33 pixels.
		"&cht=bhs"+
		"&chtt="+chartName.replace(' ','+');
		
		try
		{
			URI uri = new URI("http","chart.apis.google.com","/chart",query,null);
			String googleChartUrl = uri.toASCIIString();
			System.out.println(googleChartUrl);
	        JLabel label = new JLabel(new ImageIcon(ImageIO.read(new URL(googleChartUrl))));
	        getContentPane().add(label, BorderLayout.CENTER);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/**
	 * Builds the colors of each bar. For now we will make one color.
	 * But we could in teh future determine the progress of a task 
	 * and assign a different color for "good, late, ahead of time etc..."
	 * @param tasks
	 * @return The color part of the google query
	 */
	private String parseBarColors(List<Task> tasks)
	{
		String colors ="&chco=ffffff00,444444,";
		for (Task task : tasks)
		{
			colors += "FEF693|";
		}
		
		if(colors.endsWith("|"))
		{
			colors = colors.substring(0, colors.lastIndexOf('|'));
		}
		return colors;
	}
	
	/**
	 * Builds the percentage complete data in the google chart query
	 * @param tasks
	 * @return
	 */
	private String parsePercentCompleteData(List<Task> tasks)
	{
		String percentCompleteDataStr = "";
		for (int i=0; i<tasks.size(); i++)
		{
			Task task = tasks.get(i);
			percentCompleteDataStr+="t"+task.getPercentageComplete()+"%,000000,1,"+i+",11|";
		}
		
		percentCompleteDataStr = percentCompleteDataStr.substring(0,percentCompleteDataStr.lastIndexOf('|'));
		return percentCompleteDataStr;
	}
	
	/**
	 * Build the bars data to be included in the google chart query
	 * @param tasks
	 * @return
	 */
	private String parseBars(List<Task> tasks)
	{
		String barsDates="t:";
		
		String numOfDaysFromMinDate="";
		for (Task task : tasks)
		{
			List<Date> daysBetween = daysBetween(minDateFound, task.getStartDate(), true);
			numOfDaysFromMinDate+=daysBetween.size()+",";
		}
		
		String numOfDaysElapsed="";
		for (Task task : tasks)
		{
			numOfDaysElapsed+=task.getNumberOfDaysElapsed()+",";
		}
		
		String durations="";
		for (Task task : tasks)
		{
			durations+=task.getDuration()+",";
		}
		
		if(numOfDaysFromMinDate.endsWith(","))
		{
			numOfDaysFromMinDate=numOfDaysFromMinDate.substring(0,numOfDaysFromMinDate.lastIndexOf(','));
		}
		
		if(numOfDaysElapsed.endsWith(","))
		{
			numOfDaysElapsed=numOfDaysElapsed.substring(0,numOfDaysElapsed.lastIndexOf(','));
		}
		
		if(durations.endsWith(","))
		{
			durations=durations.substring(0,durations.lastIndexOf(','));
		}
		
		barsDates+= numOfDaysFromMinDate + "|" + numOfDaysElapsed + "|" + durations;
		return barsDates;
	}
	
	/**
	 * Builds the x-y axis part of the google chart query
	 * @param tasks
	 * @return
	 */
	private String parseXYAxis(List<Task> tasks)
	{
		String xAxis="1:|";
		String yAxis="0:|";
		//1. we iterate through the tasks to find what is the max and min date.
		// basically this is our range for the X axis.
		// While iterating we build a string that will represent the axis
		// parameter in the google chart url.
		for (Task task : tasks)
		{
			Date startDate = task.getStartDate();
			Date deadline = task.getDeadline();
			
			if(minDateFound == null || startDate.before(minDateFound))
			{
				minDateFound = startDate;
			}
			
			if(maxDateFound == null || deadline.after(maxDateFound))
			{
				maxDateFound = deadline;
			}
		}
		
		//2. Now that we found our date range for the tasks. We build the X axis string
		// We will have a mark at every 5 days.
		List<Date> daysBetween = daysBetween(minDateFound,maxDateFound,true);
		SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMM");
		for(int i=0; i<daysBetween.size(); i++)
		{
			if(i%15==0)
			{
				xAxis+=dateFormat.format(daysBetween.get(i))+"|";
			}
			else
			{
				xAxis+="|";
			}
		}
		
		//3. Finally we build the Y axis. The Y axis will simply contain all the tasks' titles.
		for (Task task : tasks)
		{
			yAxis+=task.getTitle().replace(' ','+')+"|";
		}
		
		return yAxis+xAxis;
	}
	
	/**
	 * Computes the number of days between a start date and and end date.
	 * @param startDate
	 * @param endDate
	 * @param endDateInclusive TRUE if the end date is to be included in the count, false otherwise.
	 * @return A list of all dates between the startDate and endDate
	 */
	private static List<Date> daysBetween(Date startDate, Date endDate, boolean endDateInclusive)
	{
		// assert: startDate must be before endDate
		List<Date> dates = new ArrayList<Date>();
			
		Calendar startCal = Calendar.getInstance();
		startCal.setTime(startDate);
		
		Calendar endCal = Calendar.getInstance();
		endCal.setTime(endDate);
		if(endDateInclusive)
		{
			endCal.add(Calendar.DAY_OF_MONTH, 1);
		}
			
		while (startCal.before(endCal))
		{
			dates.add(new Date(startCal.getTime().getTime()));
			startCal.add(Calendar.DAY_OF_MONTH, 1);
		}
		return dates;
	}
}
